package com.idanchuang.component.gauss.service;

import com.idanchuang.component.base.JsonResult;
import com.idanchuang.component.base.exception.common.ErrorCode;
import com.idanchuang.component.base.exception.core.ExFactory;
import com.idanchuang.component.gauss.config.IdempotentConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

/**
 * @Author: chac
 * @PackageName: com.idanchuang.component.gauss.service
 * @ClassName: Idempotent
 * @Description:
 * @Date: 2021/3/10 3:59 下午
 */
public class IdempotentService {

    private static final Logger logger = LoggerFactory.getLogger(IdempotentService.class);

    private IdempotentConfig idempotentConfig;
    private RestTemplate restTemplate;

    public IdempotentService(IdempotentConfig idempotentConfig, RestTemplate restTemplate) {
        this.idempotentConfig = idempotentConfig;
        this.restTemplate= restTemplate;
    }

    /**
     * 创建幂等键
     * @param key 幂等的key
     * @param expireTime 失效时间 单位：s
     * @return 操作结果
     * code不为成功代表系统异常
     * code为成功时，data(true/false) 代表 true-操作成功，false-已存在对应key
     */
    public JsonResult<Boolean> create(String key, Long expireTime) {
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();
        params.add("appId", this.idempotentConfig.getAppName());
        params.add("key", key);
        params.add("expire", expireTime);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(params, headers);
        return restTemplate.postForEntity(this.idempotentConfig.getGaussCreateUrl(),
                httpEntity, JsonResult.class).getBody();
    }

    /**
     *
     * @param key
     * @param expireTime
     * @return 操作结果
     * code不为成功代表系统异常
     * code为成功时 代表取消成功
     */
    public JsonResult cancel(String key, Long expireTime) {
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();
        params.add("appId", this.idempotentConfig.getAppName());
        params.add("key", key);
        params.add("expire", expireTime);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(params, headers);
        return restTemplate.postForEntity(this.idempotentConfig.getGaussCancelUrl(), httpEntity, JsonResult.class)
                .getBody();
    }

    public Boolean checkIdempotent(String key, Long expireTime) {
        JsonResult<Boolean> jsonResult;
        try {
            jsonResult = create(key, expireTime);
        } catch (Exception e) {
            logger.error("checkIdempotent error, key: {} , expireTime: {} ,", key, expireTime, e);
            cancel(key, expireTime);
            throw ExFactory.throwWith(ErrorCode.UNDEFINED_ERROR, "调用幂等接口异常");
        }

        if (!jsonResult.checkSuccess()) {
            // 幂等系统异常情况
            throw ExFactory.throwBusiness(jsonResult.getMsg());
        }
        return jsonResult.getData();
    }
}
